package com.ssy.lingxi.order.serviceimpl.platform;

import com.ssy.lingxi.common.constant.basic.EnableDisableStatus;
import com.ssy.lingxi.common.constant.order.OrderPurchaseProcessTypeEnum;
import com.ssy.lingxi.common.exception.BusinessException;
import com.ssy.lingxi.common.response.PageData;
import com.ssy.lingxi.common.response.ResponseCode;
import com.ssy.lingxi.common.response.Wrapper;
import com.ssy.lingxi.order.entity.BasePurchaseProcessDO;
import com.ssy.lingxi.order.entity.PlatformPurchaseProcessDO;
import com.ssy.lingxi.order.entity.PlatformPurchaseProcessMemberDO;
import com.ssy.lingxi.order.entity.PlatformTradeProcessDO;
import com.ssy.lingxi.order.model.constant.BasePurchaseProcessEnum;
import com.ssy.lingxi.order.model.constant.OrderServiceContants;
import com.ssy.lingxi.order.model.dto.OrderMemberQueryDTO;
import com.ssy.lingxi.order.model.vo.basic.request.OrderProcessIdVO;
import com.ssy.lingxi.order.model.vo.basic.request.OrderProcessUpdateStatusVO;
import com.ssy.lingxi.order.model.vo.platform.request.PlatformProcessMemberPageVO;
import com.ssy.lingxi.order.model.vo.platform.request.PlatformProcessUpdateVO;
import com.ssy.lingxi.order.model.vo.platform.request.PlatformProcessVO;
import com.ssy.lingxi.order.model.vo.platform.request.PlatfromProcessPageVO;
import com.ssy.lingxi.order.model.vo.platform.response.PlatformBasePurchaseProcessVO;
import com.ssy.lingxi.order.model.vo.platform.response.PlatformProcessDetailVO;
import com.ssy.lingxi.order.model.vo.platform.response.PlatformProcessPageQueryVO;
import com.ssy.lingxi.order.model.vo.process.response.BasePurchaseProcessVO;
import com.ssy.lingxi.order.repository.PlatformPurchaseProcessRepository;
import com.ssy.lingxi.order.service.base.IBaseCacheService;
import com.ssy.lingxi.order.service.base.IBasePlatformPurchaseProcessMemberService;
import com.ssy.lingxi.order.service.base.IBasePurchaseProcessService;
import com.ssy.lingxi.order.service.platform.IPlatformPurchaseProcessService;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import javax.persistence.criteria.Join;
import javax.persistence.criteria.JoinType;
import javax.persistence.criteria.Predicate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 平台后台 - 采购流程规则配置相关接口实现类
 * @author 万宁
 * @version 2.0.0
 * @date 2021-07-26
 */
@Service
public class PlatformPurchaseProcessServiceImpl implements IPlatformPurchaseProcessService {
    @Resource
    private IBaseCacheService baseCacheService;
    
    @Resource
    private IBasePurchaseProcessService basePurchaseProcessService;
    
    @Resource
    private IBasePlatformPurchaseProcessMemberService basePlatformPurchaseProcessMemberService;

    @Resource
    private PlatformPurchaseProcessRepository platformPurchaseProcessRepository;

    /**
     * 分页查询采购流程规则配置
     *
     * @param headers HttpHeaders信息
     * @param pageVO  接口参数
     * @return 查询结果
     */
    @Override
    public Wrapper<PageData<PlatformProcessPageQueryVO>> pagePurchaseProcess(HttpHeaders headers, PlatfromProcessPageVO pageVO) {
        baseCacheService.needLoginFromManagePlatform(headers);
        Pageable pageable = PageRequest.of(pageVO.getCurrent() - 1, pageVO.getPageSize(), Sort.by("createTime").descending());
        Specification<PlatformPurchaseProcessDO> specification = (Specification<PlatformPurchaseProcessDO>) (root, query, criteriaBuilder) -> {
            List<Predicate> list = new ArrayList<>();
            if(StringUtils.hasLength(pageVO.getName())) {
                list.add(criteriaBuilder.like(root.get("name").as(String.class), "%" + pageVO.getName().trim() + "%"));
            }
            Predicate[] p = new Predicate[list.size()];
            return criteriaBuilder.and(list.toArray(p));
        };

        Page<PlatformPurchaseProcessDO> pageList = platformPurchaseProcessRepository.findAll(specification, pageable);
        return Wrapper.success(new PageData<>(pageList.getTotalElements(), pageList.getContent().stream().map(process ->{
            PlatformProcessPageQueryVO queryVO = new PlatformProcessPageQueryVO();
            queryVO.setProcessId(process.getId());
            queryVO.setCreateTime(process.getCreateTime().format(OrderServiceContants.DEFAULT_TIME_FORMATTER));
            queryVO.setName(process.getName());
            queryVO.setStatus(process.getStatus());
            queryVO.setStatusName(EnableDisableStatus.getNameByCode(process.getStatus()));
            return queryVO;
        }).collect(Collectors.toList())));
    }

    /**
     * 新增采购规则页面 - 查询基础采购流程列表
     *
     * @param headers Http头部信息
     * @return 查询结果
     */
    @Override
    public Wrapper<List<PlatformBasePurchaseProcessVO>> listBasePurchaseProcess(HttpHeaders headers) {
        baseCacheService.needLoginFromManagePlatform(headers);
        return Wrapper.success(basePurchaseProcessService.listProcessByPlatform());
    }

    /**
     * 新增采购流程规则
     *
     * @param headers   HttpHeaders信息
     * @param processVO 接口参数
     * @return 新增结果
     */
    @Transactional(rollbackFor = BusinessException.class)
    @Override
    public Wrapper<Void> createPurchaseProcess(HttpHeaders headers, PlatformProcessVO processVO) {
        baseCacheService.needLoginFromManagePlatform(headers);

        //Step 1: 判断基础流程
        BasePurchaseProcessDO basePurchaseProcess = basePurchaseProcessService.findById(processVO.getBaseProcessId());
        if(basePurchaseProcess == null) {
            return Wrapper.fail(ResponseCode.ORDER_BASE_PURCHASE_PROCESS_DOES_NOT_EXIST);
        }

        //Step 2: 判断是否已经存在
        if(platformPurchaseProcessRepository.existsByProcess(basePurchaseProcess)) {
            return Wrapper.fail(ResponseCode.ORDER_PLATFORM_PURCHASE_PROCESS_EXISTS);
        }

        //Step 3: 新增
        PlatformPurchaseProcessDO purchaseProcess = new PlatformPurchaseProcessDO();
        purchaseProcess.setCreateTime(LocalDateTime.now());
        purchaseProcess.setName(processVO.getName());
        purchaseProcess.setProcess(basePurchaseProcess);
        purchaseProcess.setProcessKey(basePurchaseProcess.getProcessKey());
        purchaseProcess.setProcessType(basePurchaseProcess.getProcessType());
        purchaseProcess.setProcessKind(basePurchaseProcess.getProcessKind());
        purchaseProcess.setSkipFirstStep(basePurchaseProcess.getSkipFirstStep());
        purchaseProcess.setStatus(EnableDisableStatus.ENABLE.getCode());
        purchaseProcess.setAllMembers(processVO.getAllMembers());
        //由于关联实体时 CascadeType.DETACH, 所以要先保存一次
        platformPurchaseProcessRepository.saveAndFlush(purchaseProcess);

        // 3-1 : 校验、保存关联的会员
        Wrapper<Void> checkResult = basePlatformPurchaseProcessMemberService.checkMembers(purchaseProcess, processVO.getAllMembers(), processVO.getMembers());
        if(checkResult.getCode() != ResponseCode.SUCCESS.getCode()) {
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return Wrapper.fail(checkResult.getCode(), checkResult.getMessage());
        }

        platformPurchaseProcessRepository.saveAndFlush(purchaseProcess);
        return Wrapper.success();
    }

    /**
     * 查询采购流程规则详情
     *
     * @param headers HttpHeaders信息
     * @param idVO    接口参数
     * @return 查询结果
     */
    @Override
    public Wrapper<PlatformProcessDetailVO> getPurchaseProcess(HttpHeaders headers, OrderProcessIdVO idVO) {
        PlatformPurchaseProcessDO purchaseProcess = platformPurchaseProcessRepository.findById(idVO.getProcessId()).orElse(null);
        if(purchaseProcess == null) {
            return Wrapper.fail(ResponseCode.ORDER_PLATFORM_PURCHASE_PROCESS_DOES_NOT_EXIST);
        }

        PlatformProcessDetailVO detailVO = new PlatformProcessDetailVO();
        detailVO.setProcessId(purchaseProcess.getId());
        detailVO.setName(purchaseProcess.getName());
        detailVO.setBaseProcessId(purchaseProcess.getProcess().getId());
        detailVO.setAllMembers(purchaseProcess.getAllMembers());
        detailVO.setStatus(purchaseProcess.getStatus());
        detailVO.setStatusName(EnableDisableStatus.getNameByCode(purchaseProcess.getStatus()));
        return Wrapper.success(detailVO);
    }

    /**
     * 分页查询采购流程规则适用会员列表
     *
     * @param headers HttpHeaders信息
     * @param pageVO  接口参数
     * @return 查询结果
     */
    @Override
    public Wrapper<PageData<OrderMemberQueryDTO>> pagePurchaseProcessMembers(HttpHeaders headers, PlatformProcessMemberPageVO pageVO) {
        baseCacheService.needLoginFromManagePlatform(headers);
        PlatformPurchaseProcessDO purchaseProcess = platformPurchaseProcessRepository.findById(pageVO.getProcessId()).orElse(null);
        if(purchaseProcess == null) {
            return Wrapper.fail(ResponseCode.ORDER_PLATFORM_PURCHASE_PROCESS_DOES_NOT_EXIST);
        }

        return basePlatformPurchaseProcessMemberService.pageMembers(purchaseProcess, pageVO.getName(), pageVO.getCurrent(), pageVO.getPageSize());
    }

    /**
     * 修改采购流程规则
     *
     * @param headers  HttpHeaders信息
     * @param updateVO 接口参数
     * @return 修改结果
     */
    @Transactional(rollbackFor = BusinessException.class)
    @Override
    public Wrapper<Void> updatePurchaseProcess(HttpHeaders headers, PlatformProcessUpdateVO updateVO) {
        baseCacheService.needLoginFromManagePlatform(headers);
        PlatformPurchaseProcessDO purchaseProcess = platformPurchaseProcessRepository.findById(updateVO.getProcessId()).orElse(null);
        if(purchaseProcess == null) {
            return Wrapper.fail(ResponseCode.ORDER_PLATFORM_PURCHASE_PROCESS_DOES_NOT_EXIST);
        }

        //Step 1: 判断基础流程
        BasePurchaseProcessDO basepurchaseProcess = basePurchaseProcessService.findById(updateVO.getBaseProcessId());
        if(basepurchaseProcess == null) {
            return Wrapper.fail(ResponseCode.ORDER_BASE_PURCHASE_PROCESS_DOES_NOT_EXIST);
        }

        //Step 2: 判断是否已经存在
        if(platformPurchaseProcessRepository.existsByProcessAndIdNot(basepurchaseProcess, purchaseProcess.getId())) {
            return Wrapper.fail(ResponseCode.ORDER_PLATFORM_PURCHASE_PROCESS_EXISTS);
        }

        //Step 3: 修改
        purchaseProcess.setCreateTime(LocalDateTime.now());
        purchaseProcess.setName(updateVO.getName());
        purchaseProcess.setProcess(basepurchaseProcess);
        purchaseProcess.setProcessKey(basepurchaseProcess.getProcessKey());
        purchaseProcess.setProcessType(basepurchaseProcess.getProcessType());
        purchaseProcess.setProcessKind(basepurchaseProcess.getProcessKind());
        purchaseProcess.setSkipFirstStep(basepurchaseProcess.getSkipFirstStep());
        purchaseProcess.setAllMembers(updateVO.getAllMembers());

        // 3-1 : 校验、修改关联的会员
        Wrapper<Void> checkResult = basePlatformPurchaseProcessMemberService.updateMembers(purchaseProcess, updateVO.getAllMembers(), updateVO.getMembers());
        if(checkResult.getCode() != ResponseCode.SUCCESS.getCode()) {
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return Wrapper.fail(checkResult.getCode(), checkResult.getMessage());
        }

        platformPurchaseProcessRepository.saveAndFlush(purchaseProcess);
        return Wrapper.success();
    }

    /**
     * 修改采购流程规则状态
     *
     * @param headers  HttpHeaders信息
     * @param statusVO 接口参数
     * @return 修改结果
     */
    @Override
    public Wrapper<Void> updatePurchaseProcessStatus(HttpHeaders headers, OrderProcessUpdateStatusVO statusVO) {
        baseCacheService.needLoginFromManagePlatform(headers);
        PlatformPurchaseProcessDO purchaseProcess = platformPurchaseProcessRepository.findById(statusVO.getProcessId()).orElse(null);
        if(purchaseProcess == null) {
            return Wrapper.fail(ResponseCode.ORDER_PLATFORM_PURCHASE_PROCESS_DOES_NOT_EXIST);
        }

        purchaseProcess.setCreateTime(LocalDateTime.now());
        purchaseProcess.setStatus(statusVO.getStatus());
        platformPurchaseProcessRepository.saveAndFlush(purchaseProcess);
        return Wrapper.success();
    }

    /**
     * 删除采购流程规则
     *
     * @param headers HttpHeaders信息
     * @param idVO    接口参数
     * @return 删除结果
     */
    @Override
    public Wrapper<Void> deletePurchaseProcess(HttpHeaders headers, OrderProcessIdVO idVO) {
        baseCacheService.needLoginFromManagePlatform(headers);
        PlatformPurchaseProcessDO purchaseProcess = platformPurchaseProcessRepository.findById(idVO.getProcessId()).orElse(null);
        if(purchaseProcess == null) {
            return Wrapper.fail(ResponseCode.ORDER_PLATFORM_PURCHASE_PROCESS_DOES_NOT_EXIST);
        }

        platformPurchaseProcessRepository.delete(purchaseProcess);
        return Wrapper.success();
    }

    /**
     * 系统能力 - 新增采购流程规则配置时，根据平台后台的配置查询基础采购流程列表
     *
     * @param memberId 会员Id
     * @param roleId   会员角色Id
     * @return 查询结果
     */
    @Override
    public List<BasePurchaseProcessVO> findOrderPurchaseProcess(Long memberId, Long roleId) {
        Specification<PlatformPurchaseProcessDO> specification = (Specification<PlatformPurchaseProcessDO>) (root, query, criteriaBuilder) -> {
            List<Predicate> list = new ArrayList<>();
            list.add(criteriaBuilder.isTrue(root.get("allMembers").as(Boolean.class)));

            Join<PlatformTradeProcessDO, PlatformPurchaseProcessMemberDO> memberJoin = root.join("members", JoinType.LEFT);
            list.add(criteriaBuilder.and(criteriaBuilder.equal(memberJoin.get("memberId").as(Long.class), memberId), criteriaBuilder.equal(memberJoin.get("roleId").as(Long.class), roleId)));

            Predicate[] p = new Predicate[list.size()];
            return criteriaBuilder.or(list.toArray(p));
        };

        return platformPurchaseProcessRepository.findAll(specification).stream().filter(purchaseProcess -> purchaseProcess.getStatus().equals(EnableDisableStatus.ENABLE.getCode())).map(PlatformPurchaseProcessDO::getProcess).sorted(Comparator.comparingLong(BasePurchaseProcessDO::getId)).map(process -> {
            BasePurchaseProcessVO processVO = new BasePurchaseProcessVO();
            processVO.setBaseProcessid(process.getId());
            processVO.setProcessName(BasePurchaseProcessEnum.getNameByCode(process.getCode()));
            processVO.setProcessType(process.getProcessType());
            processVO.setProcessTypeName(OrderPurchaseProcessTypeEnum.getNameByCode(process.getProcessType()));
            processVO.setDescription(BasePurchaseProcessEnum.getRemarkByCode(process.getCode()));
            return processVO;
        }).collect(Collectors.toList());
    }
}
